package com.mxchip.livestar.ui.call


import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.trello.lifecycle2.android.lifecycle.AndroidLifecycle
import com.trello.rxlifecycle3.LifecycleProvider
import com.mxchip.livestar.R
import com.mxchip.livestar.utils.FileLog
import com.mxchip.livestar.rx.RxSchedulersHelper
import com.mxchip.livestar.base.toast
import com.mxchip.livestar.repository.RoomClientRepository
import com.mxchip.livestar.rx.RxBus
import com.mxchip.livestar.rx.RxConstant
import com.mxchip.livestar.sound.LocalRingManagement
import com.mxchip.livestar.ui.Call
import com.mxchip.livestar.ui.GroupCall
import com.mxchip.livestar.ui.P2PMultiCall
import com.mxchip.livestar.ui.P2PSingleCall
import com.mxchip.livestar.utils.MyLog
import com.videohigh.graham.SampleSDK
import com.videohigh.graham.SessionContext
import com.videohigh.graham.Term
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.fragment_green.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit

class GreenFragment : Fragment() {

    private val provider: LifecycleProvider<Lifecycle.Event> = AndroidLifecycle.createLifecycleProvider(this)

    private val roomClientRepository = RoomClientRepository

    private val dbyViewModel by activityViewModels<DbyViewModel>()
    private val screenViewModel by activityViewModels<ScreenViewModel>()
    private val roomViewModel by activityViewModels<RoomViewModel>()

    private val args: GreenFragmentArgs by navArgs()

    private val termIds = arrayListOf<String>()
    private var inviteTerms = emptyList<Term>()
    private lateinit var call: Call

    // private val sampleSDK = SampleSDK.getInstance()

    private val compositeDisposable = CompositeDisposable()

    private lateinit var leaveCallEventObservable: Observable<SessionContext>
    private lateinit var enterEventObservable: Observable<SessionContext>
    private lateinit var disconnectEventObservable: Observable<Boolean>
    private lateinit var reconnectEventObservable: Observable<Boolean>

    private val logger = FileLog.getLogger(GreenFragment::class.java)

    override fun onDestroyView() {
        super.onDestroyView()
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_green, container, false)
    }

    @SuppressLint("CheckResult")
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        this.call = args.call
        var groupId: String? = null

        when (val call = this.call) {
            is GroupCall -> {

                groupId = call.groupNumber

                head_portrait.setImageResource(R.drawable.if_icon_user)
                user_name.text = ""
                phone_state.text = "正在进入会议..."
            }
            is P2PSingleCall -> {
                this.termIds.add(call.number)

                head_portrait.setImageResource(R.drawable.if_icon_user)
                user_name.text = call.number.trimStart('0')
                phone_state.text = getString(R.string.waiting_for_answer)
            }
            is P2PMultiCall -> {
                this.termIds.addAll(call.inviteNumbers)

                head_portrait.setImageResource(R.drawable.if_icon_group_filled)
                user_name.text = getString(R.string.initiating_multi_person_meeting)
                phone_state.text = getString(R.string.other_participants) + call.inviteNumbers.joinToString(",") { it.trimStart('0') }
            }
            else -> {
                Log.e("GreenFragment", "call pojo is not right")
            }
        }

        Log.e("GreenFragment", "termIds: $termIds")

        button_hangup.setOnClickListener {
            logger.info(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(Date()) + " button_hangup.setOnClickListener")
            reqHangup()
        }

        lifecycleScope.launch {
            delay(30 * 1000)
            logger.info("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date())} AutoHangup-----30s hangup ")
            reqHangup()
        }

        //发起邀请

        //主叫收到被叫的 接听/挂断 消息
        enterEventObservable = RxBus.get().register(RxConstant.ENTER_EVENT, SessionContext::class.java)
        enterEventObservable.compose(provider.bindToLifecycle()).compose(RxSchedulersHelper.io_main())
                .subscribe(::onEnter) { error -> error.printStackTrace() }

        // 收到其他端挂断消息
        leaveCallEventObservable = RxBus.get().register(RxConstant.LEAVE_CALL_EVENT, SessionContext::class.java)
        leaveCallEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onLeaveCall) { error ->
                    run {
                        logger.error(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) +
                                " leaveCallEventObservable" + error.message)
                        error.printStackTrace()
                    }
                }

        disconnectEventObservable = RxBus.get().register(RxConstant.DISCONNECT, Boolean::class.java)
        disconnectEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onDisconnect) { error -> error.printStackTrace() }

        reconnectEventObservable = RxBus.get().register(RxConstant.RECONNECT, Boolean::class.java)
        reconnectEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onReConnect) { error -> error.printStackTrace() }


        reqInvite(termIds.toTypedArray(), groupId)

        startPlayLocalRing()

        roomViewModel.isMyselfTheOnlyOneLeft.observe(viewLifecycleOwner, Observer {

            if (it == false) {
                return@Observer
            }

            lifecycleScope.launch {
                toast("对方已挂断")
                delay(1000)
                logger.info("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date())} AutoHangup----- isMyselfTheOnlyOneLeft ")
                reqHangup()
            }
        })
    }


    override fun onDestroy() {
        super.onDestroy()

        Log.e("GreenFragment", "onDestroy")
        stopPlayLocalRing()
        RxBus.get().unregister(RxConstant.ENTER_EVENT, enterEventObservable)
        RxBus.get().unregister(RxConstant.LEAVE_CALL_EVENT, leaveCallEventObservable)
        RxBus.get().unregister(RxConstant.DISCONNECT, disconnectEventObservable)
        RxBus.get().unregister(RxConstant.RECONNECT, reconnectEventObservable)
        compositeDisposable.clear()
    }

    private fun startPlayLocalRing() {
        compositeDisposable.add(Observable.interval(0, 0, TimeUnit.MILLISECONDS)
                .compose(RxSchedulersHelper.io())
                .take(1)
                .subscribe { aLong: Long? -> LocalRingManagement.getInstance().playMusic(R.raw.called, context) })
    }

    private fun stopPlayLocalRing() {
        if (LocalRingManagement.getInstance().isPlaying) {
            LocalRingManagement.getInstance().stop()
        }
    }

    private fun reqHangup() {
        Log.e("GreenFragment", "Appli.getServerState(): ")

        stopPlayLocalRing()

        RoomClientRepository.endCall {
            dbyViewModel.join(null)
        }
    }


    //发起邀请
    private fun reqInvite(termIds: Array<String>, groupId: String?) {

        RoomClientRepository.makeCall(groupId, termIds, { session ->

            if (this.call is GroupCall) {

                lifecycleScope.launch {
                    delay(3000)
                    enterCall()
                }

            } else {
                val allInvitationsBusy = session.inviteList.size <= 1

                inviteTerms = session.inviteList.toList()

                if (allInvitationsBusy) {
                    toast("对方正忙，请稍后再呼叫")

                    lifecycleScope.launch {
                        delay(3000)
                        reqHangup()
                    }
                }
            }

        }, { code, message ->
            lifecycleScope.launch {
                toast("呼叫异常 $code $message")
            }
        })

    }

    private fun onEnter(sessionContext: SessionContext) {

        Log.e("GreenFragment", "onEnter: $sessionContext")

        val callList = sessionContext.callList
        if (!inviteTerms.isNullOrEmpty() && callList.union(inviteTerms).isNotEmpty()) {
            stopPlayLocalRing()
            enterCall()
        }
    }

    private fun enterCall() {

        roomClientRepository.enterCall({sessionContext ->

            lifecycleScope.launch {
                Log.e("GreenFragment", "callback enterCall $sessionContext")

                val action = GreenFragmentDirections.actionGreenFragmentToCallControlFragment()
                findNavController().navigate(action)
            }

        }, {code, message ->
            lifecycleScope.launch {
                toast("错误代码: $code $message")
            }
        })
    }


    private fun onLeaveCall(session: SessionContext) {
        Log.e("GreenFragment", "onLeaveCall: $session")
    }

    private fun onReConnect(v: Boolean) {
        lifecycleScope.launch {

            while (!RoomClientRepository.connected()) {
                delay(1)
            }

            RoomClientRepository.syncChannel({ session ->
                MyLog.logD(MyLog.SIGNALLING_MODEL,"GreenFragment: onReConnect: syncChannelResp ----- $session")
                if (session.callList.isNotEmpty()) {
                    enterCall()
                }
            }, { code, message ->

            })

        }

    }

    private fun onDisconnect(v: Boolean) {
        toast("当前网络差，正在尝试重连...")
    }
}
